﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Linq;
using System.Text;

namespace SourceGeneratorLibrary
{
    [Generator]
    public class AutoAttributeDependencyInjectionGenerator : IIncrementalGenerator
    {
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            // 1. 注册特性代码
            context.RegisterPostInitializationOutput(ctx =>
            {
                const string attributeSource = @"// <auto-generated />
using System;

namespace SourceGeneratorLibrary
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    internal class AutoInjectScopedAttribute : Attribute
    {
    }
}";
                ctx.AddSource("AutoInjectScopedAttribute.g.cs",
                    SourceText.From(attributeSource, Encoding.UTF8));
            });

            // 2. 创建管道：筛选带特性的类
            var classDeclarations = context.SyntaxProvider
                .CreateSyntaxProvider(
                    predicate: static (s, _) => IsCandidateClass(s),
                    transform: static (ctx, _) => GetSemanticTargetForGeneration(ctx))
                .Where(static m => m is not null);

            // 3. 收集编译信息和类声明
            var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());

            // 4. 生成代码
            context.RegisterSourceOutput(compilationAndClasses,
                static (spc, source) => Execute(source.Left, source.Right, spc));
        }

        // 快速筛选：是否为带特性的类
        private static bool IsCandidateClass(SyntaxNode node)
        {
            return node is ClassDeclarationSyntax classDeclaration &&
                   classDeclaration.AttributeLists.Count > 0;
        }

        // 语义分析：获取符号信息
        private static INamedTypeSymbol GetSemanticTargetForGeneration(GeneratorSyntaxContext context)
        {
            var classDeclaration = (ClassDeclarationSyntax)context.Node;
            var classSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclaration);

            if (classSymbol == null)
                return null;

            // 检查是否有 AutoInjectScoped 特性
            bool hasAttribute = classSymbol.GetAttributes()
                .Any(a => a.AttributeClass?.Name == "AutoInjectScopedAttribute");

            return hasAttribute ? classSymbol as INamedTypeSymbol : null;
        }

        // 生成扩展方法代码
        private static void Execute(Compilation compilation, ImmutableArray<INamedTypeSymbol> classes, SourceProductionContext context)
        {
            if (classes.IsDefaultOrEmpty)
                return;

            // 构建服务注册代码
            var registrations = new StringBuilder();
            const string indent = "            ";

            foreach (var classSymbol in classes.Distinct())
            {
                var fullTypeName = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                registrations.AppendLine($"{indent}services.AddScoped<{fullTypeName}>();");
            }

            if (registrations.Length == 0)
                return;

            // 生成扩展类
            var safeAssemblyName = compilation.AssemblyName?
                .Replace(".", "_")
                .Replace("-", "_") ?? "Generated";

            var extensionCode = $@"// <auto-generated />
using Microsoft.Extensions.DependencyInjection;

namespace SourceGeneratorLibrary
{{
    public static partial class GeneratedServicesExtension
    {{
        public static IServiceCollection AddAttributeServicesIn{safeAssemblyName}(this IServiceCollection services)
        {{
            return services.AddAttributeGeneratedServices();
        }}

        internal static IServiceCollection AddAttributeGeneratedServices(this IServiceCollection services)
        {{
{registrations}            return services;
        }}
    }}
}}";

            context.AddSource($"GeneratedServicesExtension_{safeAssemblyName}.g.cs",
                SourceText.From(extensionCode, Encoding.UTF8));
        }
    }
}
